package cn.javass.spring.chapter8;

import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import cn.javass.spring.chapter7.UserModel;
import cn.javass.spring.chapter7.dao.IUserDao;


public class HibernateTest {
    
    private static SessionFactory sessionFactory;
    
    @BeforeClass
    public static void beforeClass() {
        String[] configLocations = new String[] {
                "classpath:chapter7/applicationContext-resources.xml",
                "classpath:chapter8/applicationContext-hibernate.xml"};
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
        sessionFactory = ctx.getBean(SessionFactory.class);
    }

    @Before
    public void setUP() {
        //id自增主键从0开始
        final String createTableSql = "create memory table test" +
        "(id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, " +
        "name varchar(100))";
        sessionFactory.openSession().createSQLQuery(createTableSql).executeUpdate();
    }
    @After
    public void tearDown() {
        final String dropTableSql = "drop table test";
        sessionFactory.openSession().createSQLQuery(dropTableSql).executeUpdate();
    }
    
    @Test
    public void testFirst() {
        Session session = sessionFactory.openSession();
        Transaction transaction = null;
        try {
            transaction = beginTransaction(session);
            UserModel model = new UserModel();
            model.setMyName("myName");
            session.save(model);
        } catch (RuntimeException e) {
            rollbackTransaction(transaction);
            throw e;
        } finally {
            commitTransaction(session);
        }
    }
    
    private Transaction beginTransaction(Session session) {
        Transaction transaction = session.beginTransaction();
        transaction.begin();
        return transaction;
    }

    private void rollbackTransaction(Transaction transaction) {
        if(transaction != null) {
            transaction.rollback();
        }
    }

    private void commitTransaction(Session session) {
        session.close();
    }


    @Test
    public void testHibernateTemplate() {
        HibernateTemplate hibernateTemplate = new HibernateTemplate(sessionFactory);
        final UserModel model = new UserModel();
        model.setMyName("myName");
        hibernateTemplate.save(model);
        //hsqldb自增时，第一个是0
        Assert.assertEquals(0, model.getId());
        //通过回调允许更复杂操作
        hibernateTemplate.execute(new HibernateCallback<Void>() {
            @Override
            public Void doInHibernate(Session session) 
                throws HibernateException, SQLException {
                session.save(model);
                return null;
            }
        });
        //hsqldb自增时，第二个自然就是1
        Assert.assertEquals(1, model.getId());
    }
    
    
    @Test
    public void testBestPractice() {
        String[] configLocations = new String[] {
                "classpath:chapter7/applicationContext-resources.xml",
                "classpath:chapter8/applicationContext-hibernate.xml"};
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
        IUserDao userDao = ctx.getBean(IUserDao.class);
        UserModel model = new UserModel();
        model.setMyName("test");
        userDao.save(model);
        Assert.assertEquals(1, userDao.countAll());
    }

    @Test
    public void testCURD() {
        String[] configLocations = new String[] {
                "classpath:chapter7/applicationContext-resources.xml",
        "classpath:chapter8/applicationContext-hibernate2.xml"};
        ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
        HibernateTemplate hibernateTemplate = ctx.getBean(HibernateTemplate.class);
        UserModel2 model = new UserModel2();
        model.setMyName("test");
        insert(hibernateTemplate, model);
        select(hibernateTemplate, model);
        update(hibernateTemplate, model);
        delete(hibernateTemplate, model);
    }

    private void insert(HibernateTemplate hibernateTemplate, UserModel2 model) {
        hibernateTemplate.save(model);
    }
    
    private void select(HibernateTemplate hibernateTemplate, UserModel2 model) {
        UserModel2 model2 = hibernateTemplate.get(UserModel2.class, 0);
        Assert.assertEquals(model2.getMyName(), model.getMyName());
        List<UserModel2> list = hibernateTemplate.find("from UserModel2");
        Assert.assertEquals(list.get(0).getMyName(), model.getMyName());
        
    }

    private void update(HibernateTemplate hibernateTemplate, UserModel2 model) {
        model.setMyName("test2");
        hibernateTemplate.update(model);
        
    }

    private void delete(HibernateTemplate hibernateTemplate, UserModel2 model) {
        hibernateTemplate.delete(model);
    }


    

    
}
